
using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using GruntXProductions;
using Viper;
using Viper.Opcodes;

namespace Diamond
{
	public partial class CodeGen 
	{
		public static Assembly Assembler;
		public SymbolTable Symbols;
		public StringBuilder Output = new StringBuilder("");
		public List<SyntaxNode> AST;
		public List<string> Errors = new List<string>();
		public string ReturnType = "";
		public CodeGen()
		{
			this.Symbols = new SymbolTable();
		}
		public void BeginGeneration(List<SyntaxNode> tree)
		{
			AST = tree;
			foreach(SyntaxNode sn in AST)
			{
				if(sn is ExternalMethod)
				{
					CreateExternalMethod(sn as ExternalMethod);
				}
				else if(sn is Method)
				{
					CreateMethod(sn as Method);
				}
				else if (sn is OperatorOverload)
				{
					CreateOperator(sn as OperatorOverload);
				}
			}
            if (this.Errors.Count > 0)
                throw new CodeGenException(this.Errors.Count.ToString() + " error(s) found during compiling!");
		}
		public void CompileLine(SyntaxNode sn)
		{
			if(sn is FunctionCall)
			{
				FunctionCall fc = sn as FunctionCall;
				Call (fc);
			}
			else if (sn is Declaration)
			{
				Declaration decl = sn as Declaration;
				DeclareVarAndAssign(decl);
			}
			else if (sn is InlineIL)
			{
				InlineIL il = sn as InlineIL;
				foreach(SymbolTable.Scope sc in Symbols.scopes)
				{
					foreach(Variable v in sc.Variables)
					{
						il.IL_Code = il.IL_Code.Replace("%" + v.Name, v.RealName);
					}
				}
				vasm.MainClass.Complile(il.IL_Code,ref Assembler);
			}
			else if (sn is IfStatement)
			{
				ParseIf(sn as IfStatement);
			}
			else if (sn is WhileStatement)
			{
				ParseWhile(sn as WhileStatement);
			}
			else if (sn is ForStatement)
			{
				ParseFor(sn as ForStatement);
			}
			else if (sn is Break)
			{
				if(breakLabels.Count == 0)	
					Errors.Add("No where to break to!");
				else
				{
					Assembler.Emit(new bsr(breakLabels.Pop()));
				}
			}
			else if (sn is Return)
			{
				Return ret = sn as Return;
				if(this.ReturnType == "string")
					ParseStringExpression(ret.Value);
				else if(this.ReturnType == "int")
					ParseStringExpression(ret.Value);
				Assembler.Emit(new ret());
			}
			else if (sn is Assignment)
			{
				Assignment asn = sn as Assignment;
                Assign(asn.Name, asn.Value);
			}
		}
		
	}
}